#define _CRT_SECURE_NO_WARNINGS
#include"CentralCache.h"
#include"PageCache.h"
CentralCache CentralCache::_sInst;
// 获取⼀个⾮空的span
Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
	//先查看当前spanlist是否还有未分配得span
	Span* it = list.Begin();
	while (it != list.End())
	{
		if (it->_freeList != nullptr)
		{
			return it;
		}
		else {
			it = it->_next;
		}
	}
	//解除桶锁
	list._mtx.unlock();
	//没了只能找page cache
	PageCache::GetInstance()->_pageMtx.lock();
	//访问pagechache，获取内存片
	Span*span=PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
	span->objectsize = size;
	span->_isuse = true;
	PageCache::GetInstance()->_pageMtx.unlock();
	
	//计算span大块内存得起始位置，及其内存大小（字节数）
	char*start = (char*)(span->_pageId << PAGE_SHIFT);
	size_t bytes = span->_n << PAGE_SHIFT;
	char* end = start + bytes;
	//将内存切分成链表然后链接起来
	span->_freeList = start;
	start += size;
	void* tail = span->_freeList;
	while (start < end)
	{
		NextObj(tail) = start;
		tail = NextObj(tail);
		start += size;
	}
	NextObj(tail)=nullptr;


	int j = 0;
	void* cur = span->_freeList;
	while (cur)
	{
		cur = NextObj(cur);
		j++;
	}
	if (j != bytes/size)
	{
		int k = 0;
	}


	list._mtx.lock();
	list.PushFront(span);
	return span;
}
// 从中⼼central缓存获取⼀定数量的对象给thread cache
 size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{
	//确定目标桶
	size_t index = SizeClass::Index(size);
	//加锁
	_spanList[index]._mtx.lock();
	//寻找非空span
	Span* span = GetOneSpan(_spanList[index],size);
	assert(span);
	assert(span->_freeList);
	//从span中获取batchNum个对象
	//如果不够batchNum个，有多少拿多少
	start = span->_freeList;
	end = start;
	size_t actralnum = 1;
	size_t i = 0;
	while (i < batchNum - 1 && NextObj(end) != nullptr)//防止spanlist内span不足，必变越界访问
	{
		end = NextObj(end);
		i++;
		actralnum++;
	}
	span->_freeList = NextObj(end);
	NextObj(end) = nullptr;
	span->_useCount += actralnum;

	



	_spanList[index]._mtx.unlock();
	//返回实际获取的span块
	return actralnum;
}

 //将一定数量的对象释放到span跨度
 void CentralCache::ReleaseListTospans(void* start, size_t size)
 {
	 //std::unique_lock<std::mutex> lock(PageCache::GetInstance()->_pageMtx);
	 //确定对应索引下标
	 size_t index = SizeClass::Index(size);
	 _spanList[index]._mtx.lock();
	 while (start)
	 {
		 void* next = NextObj(start);
		 Span* span = PageCache::GetInstance()->MapObjectTospan(start);
		 NextObj(start) = span->_freeList;
		 span->_freeList = start;
		 span->_useCount--;
		 //当span使用情况为0，将span还给page cache
		 if (span->_useCount == 0)
		 {
			 _spanList[index].Erase(span);
			 span->_freeList = nullptr;
			 span->_next = nullptr;
			 span->_prev = nullptr;
			 _spanList[index]._mtx.unlock();

			 PageCache::GetInstance()->_pageMtx.lock();
			 PageCache::GetInstance()->ReleaseSpanToPagecache(span);
			 PageCache::GetInstance()->_pageMtx.unlock();

			 _spanList[index]._mtx.lock();
		 }
		 start = next;
	 }


	 _spanList[index]._mtx.unlock();
 }